package server

import (
	"fmt"
	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
	"io"
	"os"
	"path"
	"time"
)

func (m *Master) CreateSSHClient(ip string, port string, user string, password string) (*ssh.Client, error) {
	sshClient, err := ssh.Dial("tcp", ip+":"+port, &ssh.ClientConfig{
		User: user,
		Auth: []ssh.AuthMethod{
			ssh.Password(password),
		},
		Timeout:         30 * time.Second,
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	})
	return sshClient, err
}

//func (m *Master) CreateSFTPClient(ip string, port string, user string, password string) (*sftp.Client, error) {
//	sshClient, createSSHClientErr := m.CreateSSHClient(ip, port, user, password)
//	if createSSHClientErr != nil {
//		return nil, createSSHClientErr
//	}
//	sftpClient, err := sftp.NewClient(sshClient)
//	return sftpClient, err
//}

func (m *Master) WriteBytesToRemoteFile(ip string, port string, user string, password string, data []byte, remotePath string) error {
	remoteDir := path.Dir(remotePath)
	sshClient, createSSHClientErr := m.CreateSSHClient(ip, port, user, password)
	if createSSHClientErr != nil {
		return createSSHClientErr
	}
	defer sshClient.Close()
	sftpClient, newFtpClientErr := sftp.NewClient(sshClient)
	if newFtpClientErr != nil {
		return newFtpClientErr
	}
	defer sftpClient.Close()
	mkdirErr := sftpClient.MkdirAll(remoteDir)
	if mkdirErr != nil {
		m.Msg.Info("%s existed", remoteDir)
	}
	dstFile, createRemoteFileErr := sftpClient.Create(remotePath)
	if createRemoteFileErr != nil {
		return createRemoteFileErr
	}
	defer dstFile.Close()
	dstFile.Write(data)
	return nil
}

func (m *Master) UploadFile(ip string, port string, user string, password string, localPath string, remotePath string) error {
	//TODO 检测目标节点的系统情况
	_, stErr := os.Stat(localPath)
	if stErr != nil {
		return stErr
	}
	srcFile, openLocalFileErr := os.Open(localPath)
	if openLocalFileErr != nil {
		return openLocalFileErr
	}
	defer srcFile.Close()
	fileName := path.Base(localPath)
	sshClient, createSSHClientErr := m.CreateSSHClient(ip, port, user, password)
	if createSSHClientErr != nil {
		return createSSHClientErr
	}
	defer sshClient.Close()
	sftpClient, newFtpClientErr := sftp.NewClient(sshClient)
	if newFtpClientErr != nil {
		return newFtpClientErr
	}
	defer sftpClient.Close()
	/*检查远程文件夹情况*/
	remoteDirInfo, checkRemotePathStatErr := sftpClient.Stat(remotePath)
	if checkRemotePathStatErr != nil {
		mkdir_err := sftpClient.MkdirAll(remotePath)
		if mkdir_err != nil {
			return mkdir_err
		}
	} else {
		if !remoteDirInfo.IsDir() {
			msg := fmt.Sprintf("%s is not a directory", remotePath)
			return &EdhErr{Code: -1, Msg: msg}
		}
	}

	/*判断文件是否存在*/
	remoteFile := path.Join(remotePath, fileName)
	_, remoteFileStatErr := sftpClient.Stat(remoteFile)
	if remoteFileStatErr != nil {
		dstFile, createNewFileErr := sftpClient.Create(remoteFile)
		if createNewFileErr != nil {
			return createNewFileErr
		} else {
			buffer := make([]byte, 1024)
			for {
				index, rbErr := srcFile.Read(buffer)
				if rbErr != nil {
					if rbErr == io.EOF {
						break
					} else {
						return rbErr
					}
				}
				dstFile.Write(buffer[:index])
			}
		}
	} else {
		return nil
	}
	/*循环读取字节并远程发送*/
	/*TODO 是否需要断点续传*/
	return nil
}

func (m *Master) ExecShell(ip string, port string, user string, password string, shell string) ([]byte, error) {
	sshClient, createSSHClientErr := m.CreateSSHClient(ip, port, user, password)
	if createSSHClientErr != nil {
		return nil, createSSHClientErr
	}
	defer sshClient.Close()
	session, newSessionErr := sshClient.NewSession()
	if newSessionErr != nil {
		return nil, newSessionErr
	}
	defer session.Close()
	execData, execErr := session.CombinedOutput(shell)
	return execData, execErr
}
